type CStructType = new () => CStruct
type CType =
    'u8' | 'u16' | 'u32' | 'u64' |
    'i8' | 'i16' | 'i32' | 'i64' |
    'f32' | 'f64' | 'str' | CStructType

type Align = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256
type Endian = 'little' | 'big'
interface FieldMetadata {
    name: string;           // Field identifier
    ctype: CType;        // Data type descriptor
    align: Align;          // Custom alignment requirement
    elementSize?: number;    // Size of individual element
    arrLength: number;    // Array dimension (1 for scalar)
    isBigInt?: boolean;      // Indicates if the field is a BigInt
    getter?: any[]       // Reference to the function that defines the field
    setter?: Function;
    isLength?: boolean;
    includeSelf?: boolean;
}
interface CalculatedField {
    name: string;
    align: Align;
    offset: number;
    size: number;
    metadata: FieldMetadata;
}

const typeByteSizeMap = new Map<CType, { size?: number, isBigInt?: boolean, getter?: any[], setter?: Function }>([
    ['u8', { size: 1, isBigInt: false, getter: [DataView.prototype.getUint8, Uint8Array], setter: DataView.prototype.setUint8 }],
    ['u16', { size: 2, isBigInt: false, getter: [DataView.prototype.getUint16, Uint16Array], setter: DataView.prototype.setUint16 }],
    ['u32', { size: 4, isBigInt: false, getter: [DataView.prototype.getUint32, Uint32Array], setter: DataView.prototype.setUint32 }],
    ['u64', { size: 8, isBigInt: true, getter: [DataView.prototype.getBigUint64, BigUint64Array], setter: DataView.prototype.setBigUint64 }],
    ['i8', { size: 1, isBigInt: false, getter: [DataView.prototype.getInt8, Int8Array], setter: DataView.prototype.setInt8 }],
    ['i16', { size: 2, isBigInt: false, getter: [DataView.prototype.getInt16, Int16Array], setter: DataView.prototype.setInt16 }],
    ['i32', { size: 4, isBigInt: false, getter: [DataView.prototype.getInt32, Int32Array], setter: DataView.prototype.setInt32 }],
    ['i64', { size: 8, isBigInt: true, getter: [DataView.prototype.getBigInt64, BigInt64Array], setter: DataView.prototype.setBigInt64 }],
    ['f32', { size: 4, isBigInt: false, getter: [DataView.prototype.getFloat32, Float32Array], setter: DataView.prototype.setFloat32 }],
    ['f64', { size: 8, isBigInt: false, getter: [DataView.prototype.getFloat64, Float64Array], setter: DataView.prototype.setFloat64 }],
    // Single-byte storage (ASCII only). 
    // For UTF-8: Characters will be converted to bytes with 
    // truncation prevention (multi-byte sequences preserved)
    ['str', { size: 1, isBigInt: false }],
])
type Options = {
    arrLength?: number,
    align?: Align,
    isLength?: boolean,
    includeSelf?: boolean
}
abstract class CStruct {
    private static fieldHierarchy = Symbol("CStruct.fieldHierarchy");  // 增加命名空间前缀
    private static metadataFields = Symbol("CStruct.metadataFields");
    static readonly PlatformEndian: Endian = (() => {
        const buffer = new ArrayBuffer(2);
        new DataView(buffer).setUint16(0, 256, true);
        return new Uint8Array(buffer)[0] === 0 ? 'little' : 'big';
    })();
    declare pack: Align;
    declare align: Align;
    declare effectiveAlignment: Align;
    declare size: number;
    declare private [CStruct.fieldHierarchy]: FieldMetadata[][];
    declare private [CStruct.metadataFields]: FieldMetadata[];
    declare Fields: CalculatedField[];
    private static VALID_ALIGN = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256] as const;
    declare private closed: boolean;
    static Layout(attr: { pack?: Align, align?: Align } = {}): ClassDecorator {
        const { pack = 0, align = 0 } = attr;
        if (!CStruct.VALID_ALIGN.includes(pack)) {
            throw new Error(`Invalid pack value: ${pack}. Must be one of ${this.VALID_ALIGN.join(', ')}`);
        }
        if (!CStruct.VALID_ALIGN.includes(align)) {
            throw new Error(`Invalid align value: ${align}. Must be one of ${this.VALID_ALIGN.join(', ')}`);
        }
        return function <T extends Function>(target: T) {
            const proto = target.prototype as CStruct;
            if (!Object.hasOwn(proto, CStruct.metadataFields)) {
                throw new Error(`[CStruct] Invalid class "${target.name}": Empty structure detected. `
                    + `Must contain at least one field.\n`
                    + `Usage example:\n`
                    + `@CStruct.Layout()\n`
                    + `class MyStruct extends CStruct {\n`
                    + `  @CStruct.U8() myField: number = 0;\n`
                    + `}`);
            }
            // 递归合并继承链上的字段
            let hierarchy: any[] = [];
            let currentProto = proto;
            while (currentProto && currentProto !== CStruct.prototype) {
                if (Object.hasOwn(currentProto, CStruct.metadataFields)) {
                    hierarchy.unshift(currentProto[CStruct.metadataFields]);
                }
                currentProto = Object.getPrototypeOf(currentProto);
            }
            proto[CStruct.fieldHierarchy] = hierarchy;

            proto.pack = pack;
            proto.align = align;
            CStruct.calculateLayout(proto);

        }
    }
    private static field(ctype: CType, options: Options = {}): PropertyDecorator {
        const { arrLength = 1, align = 0, isLength = false, includeSelf = true } = options;
        if (!typeByteSizeMap.has(ctype) && typeof ctype !== 'function') {
            throw new Error(`[CStruct] Undefined type: ${ctype}`);
        }
        // 新增嵌套结构体验证（基于layout.test.ts的测试用例）
        if (typeof ctype === 'function') {
            const proto = ctype.prototype as CStruct;
            if (!(proto instanceof CStruct)) {
                throw new Error(`[CStruct] Invalid nested struct type: ${ctype.name}`
                    + ` (Must inherit from CStruct)`);
            }
            // 如果嵌套结构体本身是可变长度（包含动态字段）
            if (proto.closed && arrLength !== 1) {
                throw new Error(`[CStruct] Variable-length struct ${ctype.name} cannot be array`);
            }
            if (proto.effectiveAlignment === undefined) {
                CStruct.Layout()(ctype);
            }
        }

        if ((align & (align - 1)) !== 0) {
            throw new Error(`[CStruct] Invalid alignment ${align}, must be power of two`);
        }
        if (!Number.isSafeInteger(arrLength) || arrLength < 0) {
            throw new Error(`[CStruct] Invalid array length: ${arrLength}. The length must be a safe integer and ≥ 0`);
        }
        if (arrLength !== 1 && isLength) {
            throw new Error(`[CStruct] autoSize cannot be used with array fields (length=${length})`);
        }
        return (function (target: CStruct, propertyKey: string) {
            if (typeof ctype === 'function' && ctype.prototype === target) {
                throw new Error(`[CStruct] Struct cannot directly nest itself: ${propertyKey}`);
            }
            if (target.closed) {
                throw new Error(`Cannot add field after zero-length array: ${propertyKey}`);
            }
            const { size: elementSize, getter, setter, isBigInt } = typeByteSizeMap.get(ctype) || {};
            const fieldMetadata: FieldMetadata = {
                ctype,
                name: propertyKey,
                align: align as Align,
                elementSize,
                arrLength,
                isBigInt,
                getter,
                setter,
                isLength,
                includeSelf
            };
            target.getOrInitFields().push(fieldMetadata);
            if (arrLength == 0 || (typeof ctype == "function" && ctype.prototype.closed)) {
                target.closed = true;
            }
        }) as PropertyDecorator;
    }
    private static calculateLayout(target: CStruct) {
        const allFields = target[CStruct.fieldHierarchy].flat();
        let offsetTracker = 0;
        let maxAlignment = 0;
        const seenFields = new Set<string>(); // 新增字段名检测集合

        target.Fields = allFields.map((field, index) => {
            // 字段名冲突检测（新增）
            if (seenFields.has(field.name)) {
                throw new Error(`[CStruct] Duplicate field name: "${field.name}" `
                    + `(Violation of C language structure naming rules)`);
            }
            seenFields.add(field.name);

            if (field.arrLength === 0 && index !== allFields.length - 1) {
                throw new Error(`[CStruct] Variable-length field '${field.name}' must be last member`
                    + ` (Found at position ${index + 1}/${allFields.length})`);
            }
            let tmpAlign: Align = 0;
            // 处理嵌套结构体
            if (typeof field.ctype === 'function') {
                const nestedProto = field.ctype.prototype as CStruct;
                field.elementSize = nestedProto.size;  // 从原型获取已计算的 length
                const effectiveNestedAlign = target.pack > 0
                    ? Math.min(nestedProto.effectiveAlignment, target.pack)
                    : nestedProto.effectiveAlignment;
                tmpAlign = Math.max(field.align, effectiveNestedAlign) as Align;
            } else {
                tmpAlign = Math.max(field.align, field.elementSize as Align) as Align;
            }
            // C 标准对齐规则
            const fieldAlignment = target.pack == 0 ? tmpAlign : Math.min(tmpAlign, target.pack);
            const fieldAlignmentMask = fieldAlignment - 1;

            maxAlignment = Math.max(maxAlignment, fieldAlignment);

            // 对齐当前偏移
            offsetTracker = (offsetTracker + fieldAlignmentMask) & (~fieldAlignmentMask);

            // 计算字段总大小（包含数组）
            const fieldSize = field.elementSize! * field.arrLength;

            const calculated: CalculatedField = {
                name: field.name,
                align: fieldAlignment as Align,
                offset: offsetTracker,
                size: fieldSize,
                metadata: field,
            };

            offsetTracker += fieldSize;
            return calculated;
        });

        // C 标准总大小对齐（取结构体对齐设置和自然对齐的最大值）
        const structAlignment = Math.max(target.align, maxAlignment);
        const structAlignmentMask = structAlignment - 1;
        target.effectiveAlignment = structAlignment as Align;
        offsetTracker = (offsetTracker + structAlignmentMask) & (~structAlignmentMask);
        target.size = offsetTracker;
    }
    constructor() {
        // 若未使用 Layout 装饰器，设置默认布局参数并计算布局
        if (this.pack === undefined) {
            const ctor = this.constructor as Function;
            CStruct.Layout()(ctor);
        }
    }
    private getOrInitFields(): FieldMetadata[] {

        if (!Object.hasOwn(this, CStruct.metadataFields)) {
            this[CStruct.metadataFields] = [];
        }
        return this[CStruct.metadataFields] as FieldMetadata[];
    }
    serialize(endian: Endian = 'little'): Uint8Array<ArrayBuffer> {
        let buffer;
        if (this.closed) {
            const { v, offset, size, isStr } = this.calculateDynaSize(endian);
            buffer = new Uint8Array(offset + size);
            buffer.set(v, offset);
            if (isStr) {
                buffer[offset + size - 1] = 0;
            }
        } else {
            buffer = new Uint8Array(this.size);
        }
        this.writeFixedSizeField(buffer, 0, endian);
        return buffer;
    }
    private writeFixedSizeField(buffer: Uint8Array, baseOffset: number, endian: Endian) {
        const view = new DataView(buffer.buffer);
        const isLittleEndian = endian === 'little';

        for (const field of this.Fields) {
            const { arrLength, ctype, setter, elementSize, isBigInt, isLength, includeSelf } = field.metadata;
            let offset = baseOffset + field.offset;
            //因为是可变长度字段已经处理，且该字段应该是最后一个
            //所以这里不需要继续处理，直接返回
            if (arrLength === 0) return;
            // 处理长度字段的特殊逻辑
            if (isLength && arrLength === 1) {
                const endOffset = buffer.length;
                const length = endOffset - offset;
                const finalLength = includeSelf ? length : length - field.size;
                const val = isBigInt ? BigInt(finalLength) : finalLength;
                setter!.call(view, offset, val, isLittleEndian);
                continue;
            }

            const value = (this as any)[field.name];
            //嵌套结构体的处理
            if (typeof ctype === 'function') {
                // 处理结构体数组
                if (arrLength > 1) {
                    for (let i = 0; i < arrLength; i++) {
                        const elemOffset = offset + (i * elementSize!);
                        (value[i] as CStruct).writeFixedSizeField(buffer, elemOffset, endian);
                    }
                } else {
                    // 处理单个结构体
                    (value as CStruct).writeFixedSizeField(buffer, offset, endian);
                }
                continue;
            }

            //字符串的处理
            if (ctype === 'str') {
                const buf = buffer.subarray(offset, offset + field.size);
                new TextEncoder().encodeInto(value, buf);
                continue;
            }
            //长度为1时，为基本数据类型，所以这里是对基本数据类型的处理
            if (arrLength === 1) {
                const val = isBigInt ? BigInt(value) : value;
                setter!.call(view, offset, val, isLittleEndian);
                continue;
            }
            //对于数组的处理
            const isAligned = (offset & (elementSize! - 1)) === 0;
            const TypedArray = field.metadata.getter![1];
            if (isAligned && endian === CStruct.PlatformEndian && !isBigInt) {
                new TypedArray(buffer.buffer, offset, arrLength).set(value);
            } else {
                //这里使用两个分支来处理，主要目的是减少在循环内的判断。
                //因为在循环内的判断会影响性能。
                if (isBigInt) {
                    for (let i = 0; i < arrLength; i++) {
                        setter!.call(view, offset, BigInt(value[i]), isLittleEndian);
                        offset += elementSize!;
                    }
                } else {
                    for (let i = 0; i < arrLength; i++) {
                        setter!.call(view, offset, value[i], isLittleEndian);
                        offset += elementSize!;
                    }
                }
            }


        }
    }
    //处理动态长度字段。
    //返回值v为序列化后的数据，
    // offset为在整体缓冲区中的偏移量，
    // size为序列化后的数据长度，
    // isStr为是否为字符串。
    private calculateDynaSize(endian: Endian): { v: Uint8Array, offset: number, size: number, isStr?: boolean } {
        const field = this.Fields[this.Fields.length - 1];
        const { ctype, getter, arrLength, setter, elementSize, isBigInt } = field.metadata;
        const value = (<any>this)[field.name];
        if (typeof ctype === 'function') {
            if (arrLength == 0) {
                const structArray = value as CStruct[];
                const elementCount = structArray.length;
                const totalSize = elementCount * elementSize!;

                // 直接创建缓冲区写入
                const buffer = new Uint8Array(totalSize);
                let offset = 0;
                for (const elem of structArray) {
                    elem.writeFixedSizeField(buffer, offset, endian);
                    offset += elementSize!;
                }

                return {
                    v: buffer,
                    offset: field.offset,
                    size: totalSize,
                    isStr: false
                };
            } else {
                const nestedStruct = (this as any)[field.name] as CStruct;
                const nestedResult = nestedStruct.calculateDynaSize(endian);
                return {
                    v: nestedResult.v,
                    offset: field.offset + nestedResult.offset,
                    size: nestedResult.size,
                    isStr: nestedResult.isStr
                };
            }
        }

        if (ctype === 'str') {
            const strValue = (this as any)[field.name] as string;
            const encoded = new TextEncoder().encode(strValue);
            return {
                v: encoded,
                offset: field.offset,
                size: encoded.length + 1, // 保留终止符空间
                isStr: true
            };
        }

        const numericArray = (this as any)[field.name];
        const TypedArrayCtor = field.metadata.getter![1];
        const needsEndianSwap = endian !== CStruct.PlatformEndian;

        const arr = isBigInt || needsEndianSwap
            //如果是BigInt类型，这里先创建一个空数据，在随后的操作中填充这个数组
            //这么做的目的是不使用map来减少内存分配的次数。
            ? new ArrayBuffer(numericArray.length * elementSize!)
            : new TypedArrayCtor(numericArray).buffer;

        if (needsEndianSwap || isBigInt) {
            const view = new DataView(arr)
            const isLittleEndian = endian === 'little';
            let byteOffset = 0;
            if (!isBigInt) {
                for (let i = 0; i < numericArray.length; i++) {
                    setter!.call(view, byteOffset, numericArray[i], isLittleEndian);
                    byteOffset += elementSize!;
                }
            } else {
                for (let i = 0; i < numericArray.length; i++) {
                    setter!.call(view, byteOffset, BigInt(numericArray[i]), isLittleEndian)
                    byteOffset += elementSize!;
                }
            }
        }
        const v = new Uint8Array(arr);
        return { v, offset: field.offset, size: v.length };
    }
    static deserialize<T extends CStruct>(
        this: new () => T,
        buffer: Uint8Array,
        endian: Endian = 'little'
    ): T {
        const instance = new this();
        const view = new DataView(buffer.buffer);

        instance.readFromBuffer(view, buffer.byteOffset, endian);
        instance.size = buffer.length;
        return instance;
    }
    protected readFromBuffer(view: DataView, baseOffset: number, endian: Endian) {
        const isLittleEndian = endian === 'little';

        for (const field of this.Fields) {
            const { arrLength, ctype, getter, elementSize, isBigInt } = field.metadata;
            let offset = baseOffset + field.offset;

            // 处理可变长度字段（提前返回机制）
            if (arrLength === 0) {
                this.handleVariableLengthField(view, field, offset, endian);
                return; // 提前返回避免后续循环
            }

            // 预计算常用值提升性能

            const isAligned = (offset & (elementSize! - 1)) === 0;

            // 结构体处理优化
            if (typeof ctype === 'function') {
                const arr = arrLength > 1 ?
                    new Array<any>(arrLength) :
                    undefined;

                if (arr) {
                    let elemOffset = offset;
                    for (let i = 0; i < arrLength; i++) {
                        const nested = new ctype();
                        nested.readFromBuffer(view, elemOffset, endian);
                        elemOffset += elementSize!;
                        arr[i] = nested;
                    }
                    (this as any)[field.name] = arr;
                } else {
                    const nested = new ctype();
                    nested.readFromBuffer(view, offset, endian);
                    (this as any)[field.name] = nested;
                }
                continue;
            }

            // 字符串处理优化
            if (ctype === 'str') {
                const strBytes = new Uint8Array(view.buffer, offset, field.size);
                let nullIndex = -1;
                // 手动循环比 indexOf 更快
                for (let i = 0; i < strBytes.length; i++) {
                    if (strBytes[i] === 0) {
                        nullIndex = i;
                        break;
                    }
                }
                (this as any)[field.name] = new TextDecoder().decode(
                    strBytes.subarray(0, nullIndex === -1 ? field.size : nullIndex)
                );
                continue;
            }

            // 基本类型数组优化
            if (arrLength > 1) {
                const TypedArray = getter![1];
                if (isAligned && endian === CStruct.PlatformEndian && !isBigInt) {
                    (this as any)[field.name] = Array.from(new TypedArray(view.buffer, offset, arrLength));
                } else {
                    const values = new Array(arrLength);
                    for (let i = 0; i < arrLength; i++) {
                        values[i] = getter![0].call(view, offset, isLittleEndian);
                        offset += elementSize!;
                    }
                    (this as any)[field.name] = values;
                }
            } else {
                (this as any)[field.name] = getter![0].call(view, offset, isLittleEndian);
            }
        }
    }
    private handleVariableLengthField(view: DataView, field: CalculatedField, offset: number, endian: Endian) {
        const { ctype, getter, elementSize } = field.metadata;
        const maxBytes = view.byteLength - offset;

        if (typeof ctype === 'function') {
            // 处理嵌套结构体数组（动态长度）
            if (field.metadata.arrLength === 0) {
                const count = Math.floor(maxBytes / elementSize!);
                const arr = new Array(count);
                for (let i = 0; i < count; i++) {
                    const nested = new ctype();
                    nested.readFromBuffer(view, offset + i * elementSize!, endian);
                    arr[i] = nested;
                }
                (this as any)[field.name] = arr;
            } else {
                // 处理单个嵌套结构体
                const dynamicStruct = new ctype();
                dynamicStruct.readFromBuffer(view, offset, endian);
                (this as any)[field.name] = dynamicStruct;
            }
        } else if (ctype === 'str') {
            // 直接内联字符串终止符查找逻辑
            const u8 = new Uint8Array(view.buffer, offset, maxBytes);
            let terminatorPos = maxBytes;
            for (let i = 0; i < u8.length; i++) {
                if (u8[i] === 0) {
                    terminatorPos = i;
                    break;
                }
            }
            (this as any)[field.name] = new TextDecoder().decode(u8.subarray(0, terminatorPos));
        } else {
            const count = Math.floor(maxBytes / elementSize!);
            const values = new Array(count);
            for (let i = 0; i < count; i++) {
                values[i] = getter![0].call(view, offset + i * elementSize!, endian === 'little');
            }
            (this as any)[field.name] = values;
        }
    }

    static U8(options: Options = {}): PropertyDecorator {
        return this.field('u8', options);
    }
    static U16(options: Options = {}): PropertyDecorator {
        return CStruct.field('u16', options);
    }
    static U32(options: Options = {}): PropertyDecorator {
        return CStruct.field('u32', options);
    }
    static U64(options: Options = {}): PropertyDecorator {
        return CStruct.field('u64', options);
    }
    static I8(options: Options = {}): PropertyDecorator {
        return CStruct.field('i8', options);
    }
    static I16(options: Options = {}): PropertyDecorator {
        return CStruct.field('i16', options);
    }
    static I32(options: Options = {}): PropertyDecorator {
        return CStruct.field('i32', options);
    }
    static I64(options: Options = {}): PropertyDecorator {
        return CStruct.field('i64', options);
    }
    static F32(options: Omit<Options, 'isLength' | 'includeSelf'> = {}): PropertyDecorator {
        return CStruct.field('f32', options);
    }
    static F64(options: Omit<Options, 'isLength' | 'includeSelf'> = {}): PropertyDecorator {
        return CStruct.field('f64', options);
    }
    static Str(maxBytes: number = 0, align: Align = 0): PropertyDecorator {
        return CStruct.field('str', { arrLength: maxBytes, align: align });
    }
    static Struct(constructor: CStructType, options: Omit<Options, 'isLength' | 'includeSelf'> = {}): PropertyDecorator {
        return CStruct.field(constructor, options);
    }
}

export {
    CStruct,
}